package com.maniu.h265_client;


import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.view.Surface;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * @author jinyf
 */
public class VideoThread extends Thread {

    private static final String TAG = "VideoThread";
    private static final long TIMEOUT_US = 10_000;

    private MediaExtractor mExtractor;
    private MediaCodec mDecoder;
    private boolean isEndOfStream = false;
    private long mStartTimeMs = 0;


    private Surface mSurface;
    private File mSourceFile;

    public VideoThread(Surface mSurface, File mSourceFile) {
        this.mSurface = mSurface;
        this.mSourceFile = mSourceFile;
    }

    @Override
    public void run() {
        if (!mSourceFile.exists()){
            throw new NullPointerException();
        }

        mExtractor = new MediaExtractor();

        try {
            mExtractor.setDataSource(mSourceFile.getPath());
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < mExtractor.getTrackCount(); i++) {
            MediaFormat format = mExtractor.getTrackFormat(i);
            String mime = format.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("video/")) {
                mExtractor.selectTrack(i);
                try {
                    mDecoder = MediaCodec.createDecoderByType(mime);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                mDecoder.configure(format, mSurface, null, 0);
                mDecoder.start();
                break;
            }
        }

        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        while (!Thread.interrupted()) {
            if (!isEndOfStream) {
                int inIndex = mDecoder.dequeueInputBuffer(TIMEOUT_US);
                if (inIndex >= 0) {
                    ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
                    ByteBuffer buffer = inputBuffers[inIndex];
                    int sampleSize = mExtractor.readSampleData(buffer, 0);
                    if (sampleSize < 0) {
                        mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                        isEndOfStream = true;
                    } else {
                        mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
                        mExtractor.advance();
                    }
                }
            }

            int outIndex = mDecoder.dequeueOutputBuffer(info, TIMEOUT_US);
            switch (outIndex) {
                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
//                    outputBuffers = mDecoder.getOutputBuffers();
                    break;
                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                    break;
                case MediaCodec.INFO_TRY_AGAIN_LATER:
                    break;
                default:
                    while (info.presentationTimeUs / 1000 >
                            System.currentTimeMillis() - mStartTimeMs) {
                        try {
                            sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }
                    mDecoder.releaseOutputBuffer(outIndex, true);
                    break;
            }
            if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                break;
            }
        }
        mDecoder.stop();
        mDecoder.release();
        mExtractor.release();

    }
}